﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using CNRegex.Entity;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using Aspose.Cells;
using System.Data;
using System.Net.Mime;

namespace CNRegex.Web.Utility
{
	public enum ExportType
	{
		导出本页=0,
		导出全部=1
	}
	public class Export
	{
		/// <summary>
		/// 导出列
		/// </summary>
		public string ExportFields { get; set; }
		/// <summary>
		/// 导出类型
		/// </summary>
		public ExportType? ExportType { get; set; }

		public static IList<ExportAttribute> ListExportAttributes<T>()
		{
			return ListExportAttributes(typeof(T));
		}

		/// <summary>
		/// 列出所有标记ExportAttribute的属性
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		public static IList<ExportAttribute> ListExportAttributes(Type t)
		{
			MetadataTypeAttribute[] metadataTypes = t.GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
			MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault();
			PropertyInfo[] properties = metadata == null ? t.GetProperties() : metadata.MetadataClassType.GetProperties();
			Type exportAttributeType = typeof(ExportAttribute);
			List<ExportAttribute> exportAttributeList = new List<ExportAttribute>();
			for (int i = 0; i < properties.Length; i++)
			{
				object[] attributes = properties[i].GetCustomAttributes(exportAttributeType, false);
				if (attributes.Length == 0)
					continue;
				ExportAttribute temp = attributes[0] as ExportAttribute;
				temp.PropertyName = properties[i].Name;
				temp.PropertyType = properties[i].PropertyType;
				exportAttributeList.Add(temp);
			}
			return exportAttributeList;
		}

		/// <summary>
		/// 导出到Excel
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="sources"></param>
		/// <param name="export"></param>
		/// <param name="fileName"></param>
		public static void ExportExcel<T>(IList<T> sources, Export export , string fileName)
		{
			fileName = string.Format("{0}{1}", fileName, DateTime.Now.Ticks.ToString());
			Type t = typeof(T);
			List<Expression<Func<T, object>>> memberExpressions = new List<Expression<Func<T, object>>>();
			string[] array = export.ExportFields.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
			ParameterExpression paramter = Expression.Parameter(t);
			for (int i = 0; i < array.Length; i++)
			{
				MemberExpression memberExpression = Expression.Property(paramter, array[i]);
				UnaryExpression unaryExpression = Expression.Convert(memberExpression, typeof(object));
				Expression<Func<T, object>> tempExpression = Expression.Lambda<Func<T, object>>(unaryExpression, paramter);
				memberExpressions.Add(tempExpression);
			}
			ExportExcel(sources,fileName, memberExpressions.ToArray());
		}

		private static void ExportExcel<T>(IList<T> sources, string fileName, params Expression<Func<T, object>>[] members)
		{
			Workbook workbook = new Workbook();
			Worksheet sheet = workbook.Worksheets[0];
			IList<ExportAttribute> willExport = new List<ExportAttribute>();
			IList<ExportAttribute> defatulExport = ListExportAttributes<T>();
			if (members == null || members.Length == 0)
				willExport = defatulExport;
			else
			{
				for (int i = 0; i < members.Length; i++)
				{
					MemberExpression memberExpr = null;
					if (members[i].Body.NodeType == ExpressionType.Convert)
						memberExpr = ((UnaryExpression)members[i].Body).Operand as MemberExpression;
					else if (members[i].Body.NodeType == ExpressionType.MemberAccess)
						memberExpr = members[i].Body as MemberExpression;
					var temp = defatulExport.FirstOrDefault(x => x.PropertyName == memberExpr.Member.Name);
					if (temp != null)
						willExport.Add(temp);
				}
			}

			//fields order.
			willExport = willExport.OrderBy(x => x.Order).ToList();

			DataTable table = new DataTable();
			foreach (var p in willExport)
			{
				DataColumn datacolumn = new DataColumn(p.DisplayName, p.PropertyType);
				table.Columns.Add(datacolumn);
			}

			Type t = typeof(T);
			foreach (T data in sources)
			{
				DataRow row = table.NewRow();
				foreach (var p in willExport)
				{
					Object value = t.GetProperty(p.PropertyName).GetValue(data, null);
					row[p.DisplayName] = value;
				}
				table.Rows.Add(row);
			}
			sheet.Cells.ImportDataTable(table, true, "A1");
			HttpContext.Current.Response.Clear();
			workbook.Save(fileName, SaveType.OpenInExcel, FileFormatType.Excel2003, HttpContext.Current.Response);
			HttpContext.Current.Response.End();
		}

		/// <summary>
		/// 导出Excel，采用HTML Table的方法进行导出。
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="sources"></param>
		/// <param name="fileName"></param>
		/// <param name="members"></param>
		private static void ExportExcelMethod2<T>(IList<T> sources, string fileName , params Expression<Func<T, object>>[] members)
		{
			IList<ExportAttribute> willExport = new List<ExportAttribute>();
			IList<ExportAttribute> defatulExport = ListExportAttributes<T>();
			if (members == null || members.Length == 0)
				willExport = defatulExport;
			else
			{
				for (int i = 0; i < members.Length; i++)
				{
					MemberExpression memberExpr = null;
					if (members[i].Body.NodeType == ExpressionType.Convert)
						memberExpr = ((UnaryExpression)members[i].Body).Operand as MemberExpression;
					else if (members[i].Body.NodeType == ExpressionType.MemberAccess)
						memberExpr = members[i].Body as MemberExpression;
					var temp = defatulExport.FirstOrDefault(x => x.PropertyName == memberExpr.Member.Name);
					if(temp!=null)
						willExport.Add(temp);
				}
			}

			StringBuilder htmlBuilder = new StringBuilder();
			TagBuilder tdBuilder = new TagBuilder("td");
			htmlBuilder.AppendLine(
			   "<html><head><meta http-equiv=Content-Type content=\"text/html; charset=GB2312\"></head><body>")
			   .AppendLine("<table cellspacing='0' rules='all' border='1' style='border-color:#95BCDD;border-collapse:collapse;'>")
			   .AppendLine("\t<tr align='center' style='background-color:#EDF6FF;height:30px;'>");
			
			foreach (var p in willExport)
			{
				tdBuilder.SetInnerText(p.DisplayName);
				htmlBuilder.Append(tdBuilder.ToString());
			}
			htmlBuilder.Append("</tr>");

			// Content Region
			Type t = typeof(T);
			foreach (T data in sources)
			{
				htmlBuilder.AppendLine("<tr>");
				foreach (var item in willExport)
				{
					Object value = t.GetProperty(item.PropertyName).GetValue(data, null);
					tdBuilder.SetInnerText(value == null ? "" : value.ToString());
					htmlBuilder.Append(tdBuilder.ToString());
				}
				htmlBuilder.AppendLine("</tr>");
			}
			htmlBuilder.Append("</table></body></html>");

			HttpContext.Current.Response.Clear();
			HttpContext.Current.Response.Buffer = true;
			HttpContext.Current.Response.Charset = "GB2312";
			HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
			HttpContext.Current.Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.xls", fileName));
			HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
			HttpContext.Current.Response.Write(htmlBuilder.ToString());
			HttpContext.Current.Response.End();
		}

	}
}